package com.jkd.server;

import com.jkd.analysis.unpack.Unpack;
import com.jkd.analysis.unpack.impl.UnpackImpl;
import com.jkd.server.cache.ChannelMap;
import com.jkd.utils.SpringUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.concurrent.locks.ReentrantLock;

import static io.netty.channel.ChannelHandler.Sharable;

@Slf4j
//@Component
//@Sharable
public class JkSocketServerHandler extends ChannelInboundHandlerAdapter {

//    @Resource
//    private Unpack unpack;

    /**
     * 处理连接时候的操作
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        new Thread(() -> {
            Channel socketChannel = ctx.channel();
            String remoteAddress = socketChannel.remoteAddress().toString();
            if (ChannelMap.getChannelFromMap(remoteAddress) == null) {
                ChannelMap.setChannelLock(remoteAddress, new ReentrantLock());
                ChannelMap.setChannel(remoteAddress, ctx);
                log.info("client" + socketChannel.remoteAddress().toString() + " connected successful！Online: " + ChannelMap.currentOnlineDevicesNum());
            }
        }).start();
        super.channelActive(ctx);
    }

    /**
     * 服务器端 读操作
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        UnpackImpl unpackImpl = (UnpackImpl) SpringUtil.getBean("unpackImpl");
        unpackImpl.toUnpack(ctx, (String) msg);
//        new Thread(() -> unpackImpl.toUnpack(ctx, (String) msg)).start();
    }

    /**
     * 通道的数据读取完毕后就会触发此方法
     *
     * @param ctx 上下文对象，内部封装了许多有用的信息
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //刷新缓存区
        ctx.flush();
    }


    /**
     * 通道断开事件触发此方法
     *
     * @param ctx 上下文
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端 " + ctx.channel().remoteAddress() + "断开了连接");
        ChannelMap.removeDeviceFormMap(ctx.channel().remoteAddress().toString());
        /*异步的关闭和客户端的通信通道，以免浪费资源*/
        ctx.channel().closeFuture().sync();
    }

    /**
     * 规定时间内如果没有调用channelRead方法 则代表没有心跳，触发一次此方法
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws InterruptedException {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
                ChannelMap.removeDeviceFormMap(inetSocketAddress.toString());
                ctx.channel().close();
                log.info("【{}】心跳丢失，已断开连接,当前客户端数量【{}】", inetSocketAddress.getHostString(), ChannelMap.currentOnlineDevicesNum());
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        if(channel.isActive())ctx.close();
    }

}
